﻿using System.Collections;
using System.Diagnostics;
using DimensionsHelper.Common.Contracts.Services;

namespace DimensionsHelper.CommandLine.ConsoleTracer;

/// <summary>
///     表示控制台中的单行内容。
/// </summary>
public class TracerLine(int line) : NavigatorLineBase(line)
{
    protected override INavigatorRange CreateRange(INavigatorRange? prev, ConsolePosition start, string content)
    {
        var range = new ConsoleRange(this, start, prev as ConsoleRange);
        range.UpdateContent(content);
        return range;
    }
}

public class ProgressEnumerable<T>(
    IEnumerable<T> source,
    Func<T, double, string>? messageGetter) : IProgressEnumerable<T>
{
    public IEnumerator<T> GetEnumerator() => source.GetEnumerator();

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();


    public Func<T, double, string>? MessageGetter { get; } = messageGetter;
}

public class TracerProgressBar : NavigatorLineBase
{
    private readonly ConsoleRange _first;
    private readonly double _itemBoundary;
    private readonly ConsoleRange _last;
    private readonly TracerLine _logLine;
    private readonly ConsoleRange _percentageRange;

    private ConsoleRange? _current;
    private int _currentIndex;
    private double _currentPercentage;

    public TracerProgressBar(int line) : base(line + 1)
    {
        _currentIndex = -1;
        _currentPercentage = 0;
        _itemBoundary = (double)100 / ItemsCount;
        _logLine = new TracerLine(line);

        int i = ItemsCount;
        Append("[").SetForeground(ProgressColor);

        while (i > 0)
        {
            ConsoleRange range = (ConsoleRange)Append(" ");
            if (_first == null)
            {
                _first = range;
            }
            else
            {
                _last = range;
            }

            i--;
        }

        Append("]").SetForeground(ProgressColor);
        Debug.Assert(Head != null && Tail != null && _first != null && _last != null);
        // 添加百分比文字区域
        _percentageRange = new ConsoleRange(this,
            ConsolePosition.Create(line + 1, Tail.GetLocation().End.Character),
            null);
        _percentageRange.UpdateContent("0%").SetForeground(ProgressColor);
    }

    public static int ItemsCount { get; set; } = 20;

    public static ConsoleColor ProgressColor { get; set; } = ConsoleColor.White;

    public static ConsoleColor ProgressInformationColor { get; set; } = ConsoleColor.White;

    public static string ProgressItemText { get; set; } = "+";


    public bool IsFinished { get; private set; }


    public double Percentage
    {
        get => _currentPercentage;

        set
        {
            if (IsFinished)
            {
                return;
            }

            if (value > 100)
            {
                value = 100;
            }

            _currentPercentage = value;
            UpdatePercentage(value);

            if (_currentPercentage < 100)
            {
                return;
            }

            IsFinished = true;
            Finished?.Invoke(this, EventArgs.Empty);
        }
    }


    protected override INavigatorRange CreateRange(INavigatorRange? prev, ConsolePosition start, string content)
    {
        var range = new ConsoleRange(this, start, prev as ConsoleRange);
        range.UpdateContent(content);
        return range;
    }


    public event EventHandler? Finished;


    private void UpdatePercentage(double percentage)
    {
        int index = (int)(percentage / _itemBoundary);
        // 前进进度条
        while (index > _currentIndex)
        {
            _currentIndex++;

            if (_current == null)
            {
                _current = _first;
            }
            else
            {
                if (_current.Next() is ConsoleRange next && next != Tail)
                {
                    _current = next;
                }
                else
                {
                    break;
                }
            }

            _current.UpdateContent(ProgressItemText).SetForeground(ProgressColor);
        }

        _percentageRange.UpdateContent($"{percentage:0.00}%");
    }


    public void UpdateLogContent(string content)
    {
        ConsoleLocation logLoc = _logLine.GetLocation();
        int logLines = logLoc.GetLines();
        _logLine.Clear();
        INavigatorRange firstRange = _logLine.First()?.UpdateContent(content) ?? _logLine.Append(content);
        firstRange.SetForeground(ProgressInformationColor);
        int newLines = _logLine.GetLocation().GetLines();
        // 当文本行行数发生变化时，需要移动进度条行
        if (logLines == newLines)
        {
            return;
        }

        int shift = newLines - logLines;
        // 如果向上移动并且记录行的结束位置比百分比的结束位置靠后，需要额外清除余下部分
        ConsoleLocation perEnd = _percentageRange.GetLocation();
        if (shift < 0 && perEnd.End.Character < logLoc.End.Character)
        {
            ConsoleHelper.ClearText(ConsoleLocation.Create(perEnd.End, logLoc.End));
        }

        Shift(shift);
        _percentageRange.Shift(shift);
        // 如果是向下移动，移动进度条时，可能会删除掉一部分记录信息
        if (shift > 0)
        {
            firstRange.Refresh();
        }
    }
}